/*
uploading.hh
*/

#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <fcntl.h>
#include <errno.h>
#include <netinet/in.h>
#include <resolv.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <iostream>
#include <openssl/sha.h>
#include <openssl/evp.h>
#include <cstring>
#include <pthread.h>

#include "BasicRingBuffer.hh"
#include "CDCodec.hh"
#include "CryptoPrimitive.hh"
#include "socket.hh"

/*for the use of LevelDB*/
#include "leveldb/db.h"
/*for the use of Slice*/
#include "leveldb/slice.h"
/*for the use of write batch*/
#include "leveldb/write_batch.h"
/*for the use of cache*/
#include "leveldb/cache.h"
/*for the use of Bloom filter*/
#include "leveldb/filter_policy.h"

#define HASH_SIZE 32
#define BLOCK_SIZE (600000)
#define FILE_HEAD (-9)
#define BLOCKCP (-8)
#define BLOCKCP_END (-7)
#define FILE_HF (-10)
#define FILE_NOT_EXIST (-5)
#define MEM_TABLE_SIZE (16<<20)
#define BLOCK_CACHE_SIZE (32<<20)
#define BLOOM_FILTER_KEY_BITS 10
/* upload buffer size */
#define UPLOAD_BUFFER_SIZE (4*1024*1024)
/* num of upload threads */
#define UPLOAD_NUM_THREADS 4

/* upload ringbuffer size */
#define UPLOAD_RB_SIZE 2048
using namespace std;


class Uploader{
  
public:
  typedef struct {
   int filesize;
   int numOfblock;
   int left;
   }fileMDHead_t;

   typedef struct {
     char hf[32];
     }fileHF_t;

  typedef struct {
    unsigned char fingerFP[32];
    unsigned char key[32];
    int blockcpid;
    int blockcpSize;
  }blockCpMDHead_t;

  typedef struct {
    blockCpMDHead_t blockcp_header;
    unsigned char* data;
  }blockCpHeadObj_t;
   
  typedef struct {
  int type;
  union{
	fileHF_t hfObj;
    fileMDHead_t fileObj;
    blockCpHeadObj_t blockcpObj;
   };
  }Item_t; 
  
  typedef struct {
    int index;
    Uploader* obj;
  }param_uploader;



  char *uploaderMetaBuffer_;
    char *uploaderContainer_;
  int metaWP_;
  int containerWP_;
  //size of blockcp header
  int blockcpMDHeadsize_;
  int fileMDHeadsize_;
  
  RingBuffer<Item_t>* ringBuffer_;
  Socket* socket_;
  pthread_t tid_;
  Uploader(int total,int subset,int userID);
  ~Uploader();
  void indicateEnd();
  int add(Item_t item, int size);
  int performUpload(char* hf,char* buffer);
 static void* thread_handler(void* param);
};
